﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocProcessingRepository.Interfaces;
using Entities;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using ServiceInterfaces;
using Services;

namespace ServiceTests
{
    [TestFixture]
    public class CsvFileServiceTests
    {
        private ICsvFileService _target;
        private Mock<IEnclosingJobRepository> _enclosingJobRepository;


        [SetUp]
        public void SetUp()
        {
            _enclosingJobRepository = new Mock<IEnclosingJobRepository>();
            _target = new CsvFileService(_enclosingJobRepository.Object);
        }

        [Test]
        public void GetCsvReport_WhenCalled_FileContainsCorrectNumberOfColumnHeaders()
        {
            //Arrange
            
            const int totalNumberOfColumns = 14;
            var jobs = GetJobEntities(0);

            //Act

            var csvFile = _target.GetCSVReport(jobs);

            //Assert

            var header = GetCsvFileHeader(csvFile);
            var columns = GetNumberOfColumns(header);
            columns.ShouldBeEquivalentTo(totalNumberOfColumns);

        }

        [Test]
        public void GetCsvReport_WhenCalled_FileContainsEnclosingJobsColumnHeaders()
        {
            //Arrange

            var jobs = GetJobEntities(0);

            //Act

            var csvFile = _target.GetCSVReport(jobs);

            //Assert
            
            var header = GetCsvFileHeader(csvFile);

            Assert.IsTrue(header.Contains("FILENAME"));
            Assert.IsTrue(header.Contains("IMAGES"));
            Assert.IsTrue(header.Contains("SHEETS"));
            Assert.IsTrue(header.Contains("PACKS")); 
        }


        [Test]
        public void GetCsvReport_WhenCalled_ReturnCorrectNumberOfDataRows()
        {
            //Arrange
            const int expectedNumberOfRows = 6;
            var jobs = GetJobEntities(5);
            _enclosingJobRepository.Setup(job => job.GetEnclosingJobsByJobId(It.IsAny<int>())).Returns(GetEnclosingJobs(0));

            //Act

            var csvFile = _target.GetCSVReport(jobs);

            //Assert

            var numberOfRows = GetNumberOfRows(csvFile);
            numberOfRows.ShouldBeEquivalentTo(expectedNumberOfRows);
        }

        [Test]
        public void GetCsvReport_WhenJobsHaveEnclosingJobs_ReturnCorrectNumberOfRows()
        {
            //Arrange
            // 2 Jobs have 3 enclosing jobs, so 4 extra rows should be added.
            const int expectedNumberOfRows = 10;
            var jobs = GetJobEntities(5);
            _enclosingJobRepository.Setup(job => job.GetEnclosingJobsByJobId(1)).Returns(GetEnclosingJobs(0));
            _enclosingJobRepository.Setup(job => job.GetEnclosingJobsByJobId(2)).Returns(GetEnclosingJobs(3));
            _enclosingJobRepository.Setup(job => job.GetEnclosingJobsByJobId(3)).Returns(GetEnclosingJobs(0));
            _enclosingJobRepository.Setup(job => job.GetEnclosingJobsByJobId(4)).Returns(GetEnclosingJobs(3));
            _enclosingJobRepository.Setup(job => job.GetEnclosingJobsByJobId(5)).Returns(GetEnclosingJobs(0));

            //Act

            var csvFile = _target.GetCSVReport(jobs);

            //Assert
            var numberOfRows = GetNumberOfRows(csvFile);
            numberOfRows.ShouldBeEquivalentTo(expectedNumberOfRows);
        }


        private IList<JobEntity> GetJobEntities(int count)
        {
            IList<JobEntity> jobs = new List<JobEntity>();
            for (int counter = 0 ; counter < count ; counter++)
            {
                jobs.Add(new JobEntity() { JobId = counter + 1 });
            }
            return jobs;
        }

        private IList<EnclosingJob> GetEnclosingJobs(int count)
        {
            IList<EnclosingJob> enclosingJobs = new List<EnclosingJob>();
            for (int counter = 0; counter < count; counter++)
            {
                enclosingJobs.Add(new EnclosingJob(){EnclosingJobID = counter + 1});
            }
            return enclosingJobs;
        }

        private string GetCsvFileHeader(StringBuilder stringBuilder)
        {
            int index = stringBuilder.ToString().IndexOf("\n", StringComparison.Ordinal);
            var header = stringBuilder.ToString().Substring(0, index);
            return header;
        }
        
        private int GetNumberOfColumns(string row)
        {
            return row.Count(c => c == ',');
        }

        private int GetNumberOfRows(StringBuilder csvFile)
        {
            var csvFileAsString = csvFile.ToString();
            return csvFileAsString.Count(c => c == '\n');

        }
    }
}